#include "memo.h"
#include "print.h"

struct run *freelist;

void kinit ()
{
  uint pages;
  char *start;

// start at 2M
  int temp = 0x200000;
  start = (char *)temp;                                    
// assume the size of memory is 1M
  pages = 256;                                             
  myPrintf ("mem = %d bytes\n", pages * PAGE);
  memset (start, 1, pages * PAGE);
  freelist = (struct run *)start;
  freelist->len = pages * PAGE;
  freelist->next = 0;
  myPrintf ("memory start = %d: memory initilization finished\n", start);
}



//Free memory space
void kfree (char *v, int len)
{
  struct run *r, *rend, **rp, *p, *pend;

  if(len <= 0 || len % PAGE)
    panic("kfree");

// Fill with junk to catch dangling refs.
  memset(v, 1, len);

//  acquire(&kalloc_lock);
  p = (struct run*)v;
  pend = (struct run*)(v + len);
  for(rp=&freelist; (r=*rp) != 0 && r <= pend; rp=&r->next){
    rend = (struct run*)((char*)r + r->len); 
    if(r <= p && p < rend)
      panic("freeing free page");
    if(pend == r){  // p next to r: replace r with p
      p->len = len + r->len;
      p->next = r->next;
      *rp = p;
      goto out;
    }
    if(rend == p){  // r next to p: replace p with r
      r->len += len;
      if(r->next && r->next == pend){  // r now next to r->next?
        r->len += r->next->len;
        r->next = r->next->next;
      }
      goto out;
    }
  }
// Insert p before r in list.
  p->len = len;
  p->next = r;
  *rp = p;

 out:
//  release(&kalloc_lock);
  return ;
}

//creat & initial a space of memory
char *kalloc (int n)
{
  char *p;
  struct run *r, **rp;

  if(n % PAGE || n <= 0)
    panic("kalloc failed: out of memory");

//  acquire(&kalloc_lock);
  for (rp=&freelist; (r=*rp) != 0; rp=&r->next)
    {
      if(r->len == n)
        {
          *rp = r->next;
          //      release(&kalloc_lock);
          return (char*)r;
        }
      if(r->len > n)
        {
          r->len -= n;
          p = (char*)r + r->len;
          //      release(&kalloc_lock);
          return p;
        }
    }
  //  release(&kalloc_lock);
  
  myPrintf("kalloc: out of memory\n");
  return 0;
}




//panic is a terminal symbol
void 
panic (char *s)
{
  printStr (s);
  return ;
}



//set "n" bytes with "c"
void *
memset(void *dst, int c, uint n)
{
  char *d;

  d = (char*)dst;
  while(n-- > 0)
    *d++ = c;

  return dst;
}



//
void*
memmove(void *dst, const void *src, uint n)
{
  const char *s;
  char *d;

  s = src;
  d = dst;
  if(s < d && s + n > d){
    s += n;
    d += n;
    while(n-- > 0)
      *--d = *--s;
  } else
    while(n-- > 0)
      *d++ = *s++;

  return dst;
}


